<!DOCTYPE html>
<meta charset="utf-8">
<title>:scope pseudo-class tests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2359 -->
<!-- Regression test for https://github.com/jsdom/jsdom/issues/3067 -->
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2998 -->
<!-- Regression test for https://github.com/jsdom/jsdom/issues/3469 -->
<!-- Regression test for https://github.com/jsdom/jsdom/issues/3802 -->

<div>
  <p><span>hello</span></p>
  <p id="p2">hey</p>
  <div id="d2">div</div>
</div>

<div id="structure1">
  <div>
    <span id="descendant-span"></span>
  </div>
</div>

<ul id="structure2">
  <li id="alpha">Alpha</li>
  <li id="beta">
    Beta
    <ul>
      <li id="gamma">Gamma</li>
      <li id="delta">Delta</li>
    </ul>
  </li>
</ul>

<script>
"use strict";
const div = document.querySelector("div");
const div2 = document.querySelector("#d2");
const p = document.querySelector("p");
const p2 = document.querySelector("#p2");

test(() => {
  assert_equals(div.querySelector(":scope > p"), p);
  assert_equals(div.querySelector(":scope > span"), null);
}, "querySelector");

test(() => {
  assert_array_equals(div.querySelectorAll(":scope > p"), [p, p2]);
  assert_array_equals(div.querySelectorAll(":scope > span"), []);
}, "querySelectorAll");

test(() => {
  assert_equals(div.querySelector(":scope > p, :scope > div"), p);
}, "querySelector comma separated");

test(() => {
  assert_array_equals(div.querySelectorAll(":scope > p, :scope > div"), [p, p2, div2]);
}, "querySelectorAll comma separated");

// Test based on https://github.com/jsdom/jsdom/issues/2998
test(() => {
  const scopeDiv = document.getElementById("structure1");
  const result = scopeDiv.querySelector(":scope > span");
  assert_equals(result, null, ":scope > span should not match descendant span");
}, "querySelector with :scope > child should not match descendants");

// Test based on https://github.com/jsdom/jsdom/issues/3067
test(() => {
  const ul = document.getElementById("structure2");
  const result = ul.querySelectorAll(":scope > li");
  const resultIDs = Array.from(result, el => el.id);
  assert_array_equals(resultIDs, ["alpha", "beta"], ":scope > li should only match direct children");
}, "querySelectorAll with :scope > child should only match direct children");

// Test based on https://github.com/jsdom/jsdom/issues/3469
test(() => {
  const doc = new DOMParser().parseFromString('<svg><defs></defs><g id="g"></g></svg>', "image/svg+xml");
  const svg = doc.documentElement;
  const g = doc.getElementById("g");
  const result = svg.querySelectorAll("g");
  assert_array_equals([...result], [g], ":scope descend match descendants");
}, "querySelectorAll with :scope in unattached svg document");

// Test based on https://github.com/jsdom/jsdom/issues/3802
test(() => {
  const xml = `
    <bar>
      <bar id="theBar"><child-bars/></bar>
      <child-bars id="theChildBar"/>
    </bar>
  `.trim();
  const doc = new DOMParser().parseFromString(xml, "text/xml");
  const theBar = doc.getElementById("theBar");
  const childBar = doc.getElementById("theChildBar");
  for (const bar of [...doc.querySelectorAll("bar")]) {
    if (!bar.parentElement) {
      continue;
    }
    bar.parentElement.querySelector(":scope > child-bars").appendChild(bar);
  }
  assert_true(theBar.parentNode === childBar);
}, "querySelectorAll with :scope in document where element moved");

</script>
